package io.netty.example.study.server;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.example.study.server.codec.OrderFrameDecoder;
import io.netty.example.study.server.codec.OrderFrameEncoder;
import io.netty.example.study.server.codec.OrderProtocolDecoder;
import io.netty.example.study.server.codec.OrderProtocolEncoder;
import io.netty.example.study.server.codec.handler.AuthHandler;
import io.netty.example.study.server.codec.handler.MetricHandler;
import io.netty.example.study.server.codec.handler.OrderServerProcessHandler;
import io.netty.example.study.server.codec.handler.ServerIdleCheckHandler;
import io.netty.handler.flush.FlushConsolidationHandler;
import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ipfilter.IpSubnetFilterRule;
import io.netty.handler.ipfilter.RuleBasedIpFilter;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;

import javax.net.ssl.SSLException;
import java.security.cert.CertificateException;
import java.util.concurrent.ExecutionException;

/**
 * 服务器端
 */
public class Server {
    public static void main(String[] args) throws InterruptedException, ExecutionException, CertificateException, SSLException {
        // 入口
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // IO模式
        serverBootstrap.channel(NioServerSocketChannel.class);
        // 日志
        serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
        // Reactor方式 boss的线程名称
        // 各种编码器以及handle
        // serverBootstrap.handler() 为serverSocketChannel设置的handle
        // serverBootstrap.childHandler()

        NioEventLoopGroup boss = new NioEventLoopGroup(0, new DefaultThreadFactory("boss"));
        NioEventLoopGroup worker = new NioEventLoopGroup(0, new DefaultThreadFactory("work"));
        serverBootstrap.group(boss, worker);
        // 流量整形
        GlobalTrafficShapingHandler globalTrafficShapingHandler = new GlobalTrafficShapingHandler(new NioEventLoopGroup(), 100 * 1024 * 1024, 100 * 1024 * 1024);

        // 多线程执行任务
        UnorderedThreadPoolEventExecutor eventExecutors = new UnorderedThreadPoolEventExecutor(10, new DefaultThreadFactory("business"));
        // NioEventLoopGroup并没有使用多个线程处理业务
        // NioEventLoopGroup business = new NioEventLoopGroup(0, new DefaultThreadFactory("business"));
        // 可视化度量
        //  MetricHandler metricHandler = new MetricHandler();
        //  设置是否启动Nagle算法：用将小的碎片数据连接成更大的报文来提高发送效率
        serverBootstrap.childOption(NioChannelOption.TCP_NODELAY, true);

        // 设置黑名单
        IpSubnetFilterRule ipSubnetFilterRule = new IpSubnetFilterRule("127.1.0.1", 16, IpFilterRuleType.REJECT);
        RuleBasedIpFilter ruleBasedIpFilter = new RuleBasedIpFilter(ipSubnetFilterRule);
        serverBootstrap.option(NioChannelOption.SO_BACKLOG, 1024);

        // 授权操作
        AuthHandler authHandler = new AuthHandler();
        // ssl证书
        SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate();
        System.out.println(selfSignedCertificate.certificate());
        SslContext sslContext = SslContextBuilder.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()).build();

        serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                ChannelPipeline pipeline = nioSocketChannel.pipeline();
                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
                pipeline.addLast("ipFilter", ruleBasedIpFilter);
                pipeline.addLast("STHandle", globalTrafficShapingHandler);
                pipeline.addLast("ServerIdle", new ServerIdleCheckHandler());
                SslHandler sslHandler = sslContext.newHandler(nioSocketChannel.alloc());
                pipeline.addLast("ssl",sslHandler);
                pipeline.addLast("frameDecoder", new OrderFrameDecoder());
                pipeline.addLast(new OrderFrameEncoder());

                pipeline.addLast(new OrderProtocolEncoder());
                pipeline.addLast(new OrderProtocolDecoder());

                pipeline.addLast(authHandler);
                // pipeline.addLast("metricsHandler", metricHandler);
                // 优化写
                pipeline.addLast("flushHandle", new FlushConsolidationHandler(5, true));
                pipeline.addLast(new LoggingHandler(LogLevel.INFO));

                // 处理IO密集型独立线程池出来
                pipeline.addLast(eventExecutors, new OrderServerProcessHandler());
            }
        });

        // 绑定端口进行启动
        ChannelFuture channelFuture = serverBootstrap.bind(8090).sync();
        // close指的是服务器/客户端的关闭，不是单个连接的关闭。
        channelFuture.channel().closeFuture().get();
    }
}
